package com.klondike.common;

import static org.junit.Assert.*;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.Collection;

import org.junit.Test;

/**
 * TypeTools examples.
 */

public class Examples {
    static class Device {
    }

    static class Router extends Device {
    }

    static class FieldInfo<T> {
        public T primaryField;
        public T[] fields;
        public Collection<T> mutuableFields;
        public Collection<? extends T> customFields;

    }

    static class StringFieldInfo extends FieldInfo<String> {
    }

    static class GenericDAO<T, ID extends Serializable> {
        protected Class<T> persistentClass;
        protected Class<ID> idClass;

        @SuppressWarnings("unchecked")
        private GenericDAO() {
            Class<?>[] typeArguments = TypeResolver.resolveArguments(getClass(), GenericDAO.class);
            this.persistentClass = (Class<T>) typeArguments[0];
            this.idClass = (Class<ID>) typeArguments[1];
        }
    }

    static class DeviceDAO<T extends Device> extends GenericDAO<T, Long> {
    }

    static class RouterDAO extends DeviceDAO<Router> {
    }

    @Test
    public void shouldResolveLayerSuperTypeInfo() {
        RouterDAO routerDAO = new RouterDAO();
        assertSame(Router.class, routerDAO.persistentClass);
        assertSame(Long.class, routerDAO.idClass);
    }

    static class Entity<ID extends Serializable> {
        ID id;

        void setId(ID id) {
        }
    }

    static class SomeEntity extends Entity<Long> {
    }

    @Test
    public void shouldResolveTypeFromFieldDeclaration() throws Exception {
        Type fieldType = Entity.class.getDeclaredField("id").getGenericType();
        assertSame(Long.class, TypeResolver.resolveClass(fieldType, SomeEntity.class));
    }

    @Test
    public void shouldResolveTypeFromMethodDeclaration() throws Exception {
        Type mutatorType = Entity.class.getDeclaredMethod("setId", Serializable.class).getGenericParameterTypes()[0];
        assertSame(Long.class, TypeResolver.resolveClass(mutatorType, SomeEntity.class));
    }

    @Test
    public void shouldResolveFieldType() throws Exception {
        Type primaryFieldType = FieldInfo.class.getDeclaredField("primaryField").getGenericType();
        Type fieldsType = FieldInfo.class.getDeclaredField("fields").getGenericType();
        Type mutuableFields = FieldInfo.class.getDeclaredField("mutuableFields").getGenericType();
        Type customFields = FieldInfo.class.getDeclaredField("customFields").getGenericType();
        assertSame(String.class, TypeResolver.resolveClass(primaryFieldType, StringFieldInfo.class));
        assertSame(String[].class, TypeResolver.resolveClass(fieldsType, StringFieldInfo.class));
        assertSame(Collection.class, TypeResolver.resolveClass(mutuableFields, StringFieldInfo.class));
        assertSame(Collection.class, TypeResolver.resolveClass(customFields, StringFieldInfo.class));

    }
}